package seatiger.tomcat.catalina.core;

import seatiger.tomcat.catalina.*;
import seatiger.tomcat.catalina.util.LifecycleSupport;
import seatiger.tomcat.util.StringManager;

import javax.servlet.ServletException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 管道的实现
 */
public class StandardPipeline implements Pipeline,Lifecycle,Contained {

    protected String info = "seatiger.apache.catalina.core.StandardPipeline/1.0";

    private Valve basic;
    @Deprecated
    private List<Valve> valves = new ArrayList<>();
    private Container container;
    private LifecycleSupport lifecycle = new LifecycleSupport(this);

    /**
     * 管道中第一个执行的阀
     */
    protected Valve first = null;

    protected static StringManager sm = StringManager.getManager(Constants.PACKAGE_CORE);

    public StandardPipeline(Container container){
        setContainer(container);
    }

    private volatile boolean started = false;

    @Override
    public Valve getBasic() {
        return this.basic;
    }

    @Override
    public void setBasic(Valve valve) {
        setValueContainer(valve);
        this.basic = valve;
    }

    @Override
    public void addValve(Valve valve) {
        synchronized (valves){
            setValueContainer(valve);
            if (first == null) {
                first = valve;
                valve.setNext(basic);
            } else {
                //其实就是一个链表
                Valve current = first;
                while (current != null) {
                    if (current.getNext() == basic) {
                        current.setNext(valve);
                        valve.setNext(basic);
                        break;
                    }
                    current = current.getNext();
                }
            }
            //这里逻辑保留，使用HttpConnector 会使用全有的阀逻辑处理
            valves.add(valve);
        }
    }

    @Override
    public void removeValve(Valve valve) {
        synchronized (valves){
            valves.remove(valve);
        }
    }

    @Override
    public Valve[] getValves() {
        return valves.toArray(new Valve[valves.size()]);
    }

    @Override
    @Deprecated
    public void invoke(Request request, Response response) throws IOException, ServletException {
        new StandardPipelineValveContext().invokeNext(request,response);
    }

    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }

    @Override
    public List<LifecycleListener> findLifecycleListeners() {
        return lifecycle.findLifecycleListeners();
    }

    @Override
    public void removeLifecycleListener(LifecycleListener listener) {
        lifecycle.removeLifecycleListener(listener);
    }

    @Override
    public void start() throws LifecycleException {
        if (started){
            throw new LifecycleException(sm.getString("standardPipeline.alreadyStarted"));
        }
        //触发启动前的事件
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
        started = true;
        System.out.println("starting..... " + info);
        //启动阀
        startComponents(valves);
        //启动基础阀
        startComponents(basic);
        lifecycle.fireLifecycleEvent(START_EVENT, null);
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
    }

    @Override
    public Container getContainer() {
        return container;
    }

    @Override
    public void setContainer(Container container) {
        this.container = container;
    }

    @Deprecated
    private class StandardPipelineValveContext implements ValveContext{
        int stage = 0;
        @Override
        public String getInfo() {
            return info;
        }

        @Override
        public void invokeNext(Request request, Response response) throws IOException, ServletException {
            int subscript = stage;
            stage++;
            if (subscript < valves.size()){
                valves.get(subscript).invoke(request,response,this);
            }else if(subscript == valves.size() && basic != null){
                basic.invoke(request,response,this);
            }else {
                throw new ServletException(sm.getString("standardPipeline.noValve"));
            }
        }
    }

    private void setValueContainer(Valve valve){
        //如果实现阀的类，也实现了Contained，就将容器关联对应的阀
        if (valve instanceof Contained){
            Contained contained = (Contained) valve;
            contained.setContainer(container);
        }
    }

    @Override
    public void stop() throws LifecycleException {
        if (!started){
            throw new LifecycleException("standardPipeline.notStarted");
        }
        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
        started = false;
        stopComponents(basic);
        for (Valve v : valves){
            stopComponents(v);
        }
        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
    }

    /**
     * 获取第一个阀，如果没有则取基础阀
     * @return
     */
    @Override
    public Valve getFirst() {
        if (first != null) {
            return first;
        }
        return basic;
    }
}
